<script setup>
import {ElementUtils} from "@/assets/js/ElementUtils";
import {setWindowTitle} from "@/assets/js/TitleUtils";
import {setupMapActions, setupMapState} from "@/assets/js/vuexUtils";
import AttachmentDialog from "@/components/common/dialog/AttachmentDialog.vue";
import BbsCodeDialog from "@/components/common/dialog/BbsCodeDialog.vue";
import PostFormDialog from "@/components/common/dialog/PostFormDialog.vue";
import ReplyLine from "@/components/read/ReplyLine.vue";
import TopicOperations from "@/components/read/TopicOperations.vue";
import {routeNames} from "@/router";
import {nextTick, onMounted, onUnmounted, ref, watch} from "vue";
import {useRoute, useRouter} from "vue-router";
import ReputationDialog from "@/components/common/dialog/ReputationDialog.vue";
import {KeyPressListener} from "@ginstone/common-utils/dist/src/utils/KeyPressListener";
import {useStore} from "vuex";
import {PostAction} from "@ginstone/nga-api/dist/src/enums/PostAction";
import HotkeyDialog from "@/components/common/dialog/HotkeyDialog.vue";
import {DomUtils} from "@/assets/js/DomUtils";
import {AccountStatus} from "@ginstone/nga-api/dist/src/enums/AccountStatus";
import BlockedRepliesDialog from "@/components/common/dialog/BlockedRepliesDialog.vue";
import {PostUtils} from "@/assets/js/PostUtils";

const {readTopic, readReply} = setupMapActions("Read", ["readTopic", "readReply"])
const {cache} = setupMapState("Read", ['cache']);


const route = useRoute()
const router = useRouter()
const store = useStore();
// 响应数据
const data = ref({});
// 主题数据
const topic = ref();
const forum = ref();
// loading动画
let loading;
// 选中的元素id
const selectedId = ref();
// 选中的回复
const selectedReply = ref();

const getUserInfo = (id) => store.dispatch("User/userInfoGetById", {id})

setWindowTitle("回复列表")
const showDialog = (name, data) => store.commit("Dialog/showDialog", {name, data})

/**
 * 根据ID 选中并滚动到一个回复
 * @param elementId 元素id
 */
const selectById = (elementId) => {
  const e = document.getElementById(elementId)
  if (e) {
    selectedId.value = elementId
    // const options = {behavior: "smooth", block: "center", inline: "center"};
    // e.scrollIntoView(options)
    // 偏移量
    const offset = 80
    let target = e.offsetTop === 0 ? e.offsetParent : e;
    window.scrollTo({behavior: "smooth", top: target.offsetTop - offset})

    const id = Number(elementId.substring(1))
    if (data.value.hasOwnProperty('replies')) {
      const replies = data.value.replies
      if (elementId.startsWith("P")) {
        selectedReply.value = replies.filter(i => i.replyId === id)[0]
      }
      if (elementId.startsWith("F")) {
        selectedReply.value = replies.filter(i => i.floorNumber === id)[0]
      }
    }
  }
}

const getParamsFromSelectedReply = () => {
  if (!selectedReply.value) {
    return undefined
  }
  return {
    tid: selectedReply.value.topicId,
    pid: selectedReply.value.replyId,
  }
}


/**
 * 获取基准元素id
 * @param elements 元素列表
 * @returns {*}
 */
const getReferenceId = (elements) => {
  if (selectedId.value && DomUtils.isInView(document.getElementById(selectedId.value))) {
    //   已经有选中的元素Id,且在视野内
    return selectedId.value;
  }
  // 否则返回视野内的第一个元素
  return elements.filter(e => DomUtils.isInView(e))[0]?.id
}
/**
 * 纵向滚动
 * @param next 步长和方向
 */
const scrollToId = (next) => {
  // 所有回复元素
  const elements = [...document.getElementsByClassName('reply-line-border')].filter(i => i.id);
  // 所有回复元素的id
  const idArray = elements.map(i => i.id)
  // 基准id
  const referenceId = getReferenceId(elements);
  if (referenceId) {
    // 当前位置
    const index = referenceId ? idArray.indexOf(referenceId) : -1;
    // 目标位置
    const targetIndex = Math.min(Math.max(0, index + next), elements.length - 1);
    // 目标id
    const targetId = idArray[targetIndex]
    selectById(targetId)
  }
}
// 应用响应结果
const applyResult = (res, force) => {
  console.log(res)
  data.value = res;
  topic.value = res.topicInfo;
  forum.value = res.forum;
  setWindowTitle(res.topicInfo.title + " - 回复列表")

  //获取用户信息
  if (res.userContext && res.userContext.userInfo) {
    for (let [id, userInfo] of res.userContext.userInfo) {
      if (userInfo.accountStatus !== AccountStatus.UNREGISTERED) {
        getUserInfo(id)
      }
    }
  }


  // 如果不是刷新请求, 且路由有hash, 尝试滚动到hash
  if (!force && route.hash) {
    const hash = route.hash.substring(1)
    // 目标元素
    nextTick(() => {
      setTimeout(() => {
        if (document.getElementById(hash)) {
          selectById(hash)
        } else if (hash.startsWith("P")) {
          // 尝试准备回复查看其状态
          store.dispatch("Post/prepare", PostUtils.buildPrepareParams(PostAction.REPLY, {tid: res.topicInfo.topicId, pid: Number(hash.substring(1))})).then(res => {
            ElementUtils.notice({
              type: 'warning',
              message: "该回复可见, 但不在视野中, 可能不在本页或被屏蔽",
            })
          }).catch(ElementUtils.exceptionHandler)
        } else {
          console.warn("未发现hash: " + hash)
          ElementUtils.notice({
            title: "未找到指定回复",
            message: "该回复可能: 被隐藏/审核中/审核不通过",
            type: "warning",
          })
        }
      }, 1000)
    })
  }
}

const request = (route, force) => {

  // loading为undefined时才创建新的loading动画
  !loading && (loading = ElementUtils.loading({target: "#content",}));

  const method = route.name === routeNames.read.topic ? readTopic : readReply
  const p = getParams(route)
  const params = route.name === routeNames.read.topic ? {params: p, force} : {pid: p, force}
  return method(params).then(res => {
    // 如果page为e重定向到指定页
    const query = {...route.query}
    if (query.page === 'e') {
      query.page = res.pageData.page
      // 删除单个缓存
      let p = {tid: params.params.tid, page: res.pageData.page.toString()}
      cache.value.remove(p)
      router.push({query, hash: route.hash})
    } else {
      applyResult(res, force)

    }
    return res;
  }).catch(ElementUtils.exceptionHandler)
      .finally(() => {
        loading.close();
        loading = undefined;
      })
}
// 刷新
const refreshRequest = () => {
  return request(route, true).then(res => {
    if (res) {
      ElementUtils.notice({message: "刷新成功"})
    }
  })
}
// 根据路由生成参数
const getParams = (route) => {
  const id = Number(route.params.id);
  if (route.name === routeNames.read.reply) {
    return id;
  }
  return {
    tid: id,
    page: route.query.page,
    authorid: route.query.authorId,
  }
}
// 快捷键触发条件
const condition = (e) => {
  // console.log(e)
  const {target} = e
  // 输入框不触发
  return !target.hasOwnProperty("cmView") && target.nodeName !== 'INPUT' && target.localName !== 'input'
}

//赞踩请求
const topicRecommend = (topicId, replyId, value) => {
  return store.dispatch("Read/topicRecommend", {topicId, replyId, value})
}

// 回复操作
const actions = [
  {
    name: "选择上一个回复",
    event: {code: "KeyW", condition}, method: () => {
      scrollToId(-1);
    },
  }, {
    name: "选择下一个回复",
    event: {code: "KeyS", condition}, method: () => {
      scrollToId(1)
    },
  }, {
    name: "选择第一个回复",
    event: {code: "KeyW", shiftKey: true, condition}, method: () => {
      scrollToId(-20);
    },
  }, {
    name: "选择最后一个回复",
    event: {code: "KeyS", shiftKey: true, condition}, method: () => {
      scrollToId(20);
    },
  }, {
    name: "快捷回复选中的回复",
    event: {code: "KeyR", condition}, method: () => {
      if (selectedReply.value) {
        showDialog('post-form', {action: PostAction.REPLY, params: getParamsFromSelectedReply()})
      }
    },
  }, {
    name: "快捷引用选中的回复",
    event: {code: "KeyQ", condition}, method: () => {
      if (selectedReply.value) {
        showDialog('post-form', {action: PostAction.QUOTE, params: getParamsFromSelectedReply()})
      }
    },
  }, {
    name: "快捷评论选中的回复",
    event: {code: "KeyT", condition}, method: () => {
      if (selectedReply.value) {
        const params = getParamsFromSelectedReply();
        params.comment = 1
        showDialog('post-form', {action: PostAction.REPLY, params})
      }
    },
  }, {
    name: "快捷回复(主题)",
    event: {code: "KeyR", shiftKey: true, condition}, method: () => {
      if (topic.value) {
        showDialog('post-form', {action: PostAction.REPLY, params: {tid: topic.value.topicId}})
      }
    },
  }, {
    name: "点赞选中的回复",
    event: {code: "KeyZ", condition}, method: () => {
      if (selectedReply.value) {
        const {tid, pid} = getParamsFromSelectedReply();
        topicRecommend(tid, pid, 1).then(value => {
          if (value) selectedReply.value.agreeCount += value;
        })
      }
    },
  }, {
    name: "点踩选中的回复",
    event: {code: "KeyC", condition}, method: () => {
      if (selectedReply.value) {
        const {tid, pid} = getParamsFromSelectedReply();
        topicRecommend(tid, pid, -1).then(value => {
          if (value) selectedReply.value.agreeCount += value;
        })
      }
    },
  },
]


/**
 * 跳转到指定页
 * @param page
 */
const goPage = (page) => {
  if (data.value && data.value.hasOwnProperty('pageData')) {
    DomUtils.scrollTop();
    const {totalPage} = data.value.pageData
    page = Math.max(1, page);
    page = Math.min(totalPage, page);
    const query = {...route.query, page}
    router.push({query});
  }
}
// 导航热键

const pageActions = [
  {
    name: "前一页",
    event: {code: "KeyA", condition}, method: () => {
      const page = route.query.page ? Number(route.query.page) : 1;
      goPage(page - 1)
    },
  }, {
    name: "后一页",
    event: {code: "KeyD", condition}, method: () => {
      const page = route.query.page ? Number(route.query.page) : 1;
      goPage(page + 1)
    },
  }, {
    name: "第一页",
    event: {code: "KeyA", shiftKey: true, condition}, method: () => {
      goPage(1)
    },
  }, {
    name: "最后一页",
    event: {code: "KeyD", shiftKey: true, condition}, method: () => {
      goPage(Number.MAX_VALUE)
    },
  }, {
    name: "刷新",
    event: {code: "KeyR", altKey: true, condition}, method: () => {
      refreshRequest()
    },
  }, {
    name: "退出主题",
    event: {code: "KeyQ", shiftKey: true, condition}, method: () => {
      if (topic.value && topic.value.colTopic) {
        const id = topic.value.colTopic.topicId
        router.push({name: routeNames.thread.colList, params: {id}})
      } else if (forum.value) {
        const id = forum.value.forumId
        router.push({name: routeNames.thread.forumList, params: {id}})
      }
    },
  },
]
// 快捷键监听器
const keyListener = new KeyPressListener(actions, undefined, false);
const pageKeyListener = new KeyPressListener(pageActions, undefined, false);
const triggerType = "keydown"

onMounted(() => {
  request(route);
  // 快捷键注册
  window.addEventListener(triggerType, keyListener.listener, false)
  window.addEventListener(triggerType, pageKeyListener.listener, false)
})

onUnmounted(() => {
  window.removeEventListener(triggerType, keyListener.listener)
  window.removeEventListener(triggerType, pageKeyListener.listener)
})

watch(route, (nv) => {
  request(nv)
})
const goBack = () => {
  console.log('go back')
}
</script>

<template>
  <div id="content" style="text-align: left">
    <!--顶部操作区-->
    <topic-operations :data="data" :hot-key="[...actions,...pageActions]" @refresh="refreshRequest"/>
    <!--回复列表-->
    <div v-show="data.replies" class="reply-lines-border">
      <!--每一行回复-->
      <reply-line v-for="(item,index) in data.replies"
                  :class="store.getters['Config/getRowClass'](index)"
                  :hash="$route.hash"
                  :reply="item"
                  :selected-id="selectedId"
                  :topic="topic"
                  :user-context="data.userContext"
                  @refresh="refreshRequest"
      />
    </div>
    <!--底部操作区-->
    <topic-operations :data="data" :hot-key="[...actions,...pageActions]" placement="bottom" @refresh="refreshRequest"/>

    <!--源代码弹窗-->
    <bbs-code-dialog/>
    <!--附件列表弹窗-->
    <attachment-dialog/>
    <!--快捷回复弹窗-->
    <post-form-dialog/>
    <!--声望弹窗-->
    <reputation-dialog/>
    <!--热键提示-->
    <hotkey-dialog/>
    <!--    被屏蔽的回复弹窗-->
    <blocked-replies-dialog/>
  </div>
</template>

<style scoped>
#content {
  min-height: 300px;
}

</style>